package cn.boodqian.airreport;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import org.apache.commons.lang3.time.FastDateFormat;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;

import cn.boodqian.utils.GAERequest;
import cn.boodqian.utils.Log;

import android.content.Context;
import android.content.SharedPreferences.Editor;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.preference.PreferenceManager;

public class GlobalData {
	// Static Data
    public static final int HISTORY_TIME_INDEX_HOUR = 0;
    public static final int HISTORY_TIME_INDEX_DAY = 1;
    public static final int HISTORY_TIME_INDEX_MONTH = 2;
	public static String[] gItemNameList = new String[] {"pm25", "pm10", "so2", "no2", "co", "o3"};
	public static String[] gItemDisplayNameList = new String[] {"PM2.5", "PM10", "SO2", "NO2", "CO", "O3"};
	public static HashMap<String, Integer> gTimeTypeMap = new HashMap();
	public static HashMap<String, Integer> gTimeLengthMap = new HashMap();
	static {
	    gTimeTypeMap.put("hour", Calendar.HOUR_OF_DAY);
	    gTimeTypeMap.put("day", Calendar.DAY_OF_MONTH);
	    gTimeTypeMap.put("month", Calendar.MONTH);
	    
	    gTimeLengthMap.put("hour", 24);
	    gTimeLengthMap.put("day", 30);
	    gTimeLengthMap.put("month", 12);
	}
	// http://www.wahart.com.hk/rgb.htm
	// CornflowerBlue, Gold, SeaGreen, IndianRed
	public static long[] gItemDisplayColorList = new long[] {0xff6495ED, 0xffFFD700, 0xff2E8B57, 0xffcd5c5c, 0xff97FFFF, 0xffAB82FF};
	public static String gGAEProject = "airdata2-feed.appspot.com";
	//public static String gGAEProject = "airdata-boodqian.appspot.com";
	public static String gUpdateHost = "boodqian-updateserver.googlecode.com";
	public static String gUpdatePath = "/svn/trunk/airreport/update.js";
	public static String gDebugUpdatePath = "/svn/trunk/debug/update.js";
	public static String gApkHost = "http://boodqian-updateserver.googlecode.com/svn/trunk/airreport/";
	public static String gPrefName = "AirreportProfileActivity";
	
	// Need to try best to keep these during update
	public static ArrayList<String> gProfileList = null;
	
	/** 
	 * Normal saved data, could be lost during update
	 */
	public static ArrayList<HashMap<String, String>> gLocationList = null;
	// { locId => { type ("hour"/"day"/"month") => airdata } }
	public static  HashMap<String, HashMap<String, AirData>> gAirdataHash = new HashMap();
	public static  int gLastServerMessageCode = 0;
	public static long gLastUpdateMessageTime = 0;
	public static int gLastLocationCode = 3; // Location version
	
	// No save data
	public static boolean gLocationNeedUpdate = false;
	public static boolean gIsFirstRun = false;
	
	//private Gson mGson = new GsonBuilder().setDateFormat(DateFormat.FULL).create();
	public final static Gson gGson = new GsonBuilder().setDateFormat("yyyy/MM/dd HH:mm:ss Z").create();
	
	public static void restoreLocationPrefs( Activity activity )
	{
		SharedPreferences prefs = activity.getSharedPreferences(gPrefName, Context.MODE_PRIVATE);
		
		try {
			JsonParser parser = new JsonParser();
			JsonArray array = parser.parse(prefs.getString("location_list", "")).getAsJsonArray();
			gLocationList = new ArrayList<HashMap<String,String>>();
			for(JsonElement e:array) {
				HashMap<String, String> map = gGson.fromJson(e, HashMap.class);
				gLocationList.add(map);
			}
			if (gLocationList != null && gLocationList.size()>0) {
				Log.i("gLocationList Restored");
			}
		} catch (Exception e) {
			gLocationList = new ArrayList<HashMap<String,String>>();
			e.printStackTrace();
			Log.e(e.getLocalizedMessage());
		}
		
		gLastLocationCode = prefs.getInt("last_location_code", gLastLocationCode);
		gLocationNeedUpdate = prefs.getBoolean("location_need_update", true);
	}
		
	public static void restorePrefs( Activity activity )
	{
		Log.i("restoring data");
		restoreLocationPrefs(activity);
		
		SharedPreferences prefs = activity.getSharedPreferences(gPrefName, Context.MODE_PRIVATE);
			
		String strProfileList = prefs.getString("profile_list", "[]");
		gProfileList = gGson.fromJson(strProfileList, ArrayList.class);
		if (gProfileList!=null && gProfileList.size()>0) {
			Log.i("gProfileList Restored");
		} else {
			gProfileList = new ArrayList<String>();
		}
		
		String version = prefs.getString("version", "");
		String currentName = getVersionName(activity);
		if( currentName.compareTo(version)!=0) {
			Log.i(String.format("Version names (%s vs %s) do not match",version,currentName));
			gIsFirstRun = true;
			gLocationNeedUpdate = true; // Always try to refresh location list after an update
			return;
		}
        gIsFirstRun = false;

		try {
			String strAirdataHash = prefs.getString("airdata", "{}");
		    Type type = new TypeToken<HashMap<String,HashMap<String, AirData>>>() {}.getType();
			gAirdataHash = gGson.fromJson(strAirdataHash, type);
			if( gAirdataHash == null ) gAirdataHash = new HashMap();
			if (gAirdataHash.size()>0) {
				Log.i( "gAirdataHash Restored");
				Log.i("gAirdataHash = " + gAirdataHash.keySet().toString());
			}
		} catch (Exception e) {
			gAirdataHash = new HashMap();
			e.printStackTrace();
		}
		gLastServerMessageCode = prefs.getInt("last_server_message_code", 0);
		gLastUpdateMessageTime = prefs.getLong("last_update_message_time", 0);
		Calendar cal = Calendar.getInstance();
		cal.setTimeInMillis(gLastUpdateMessageTime);
		FastDateFormat fmt = FastDateFormat.getInstance("yyyy-MM-dd mm:ss", Locale.US);
		Log.i( String.format( "Restroed last prompt time: %s", fmt.format(cal) ) );
		GAERequest.mLastIPIndex = prefs.getInt("last_ip_index", 0);
		
//		String ips = mPrefs.getString("google_ips", "");
//		if( ips.length() > 0 )
//			Log.i( "Google IPs Restored");
//		Log.i(ips);
//		GAERequest.mIPs = TextUtils.split(ips, "\\|");
	}
	
	public static void saveLocationPrefs( Activity activity )
	{
		if( gLocationList == null ) return;
		
		SharedPreferences prefs = activity.getSharedPreferences(gPrefName, Context.MODE_PRIVATE);
		Editor editor = prefs.edit();
		
		editor.putString("location_list", gGson.toJson(gLocationList));
		editor.putInt("last_location_code", gLastLocationCode);
		editor.putBoolean("location_need_update", gLocationNeedUpdate);
		editor.commit();
	}
	
	public static void savePrefs( Activity activity )
	{
		Log.i("saving data");
		saveLocationPrefs(activity);
		
		SharedPreferences prefs = activity.getSharedPreferences(gPrefName, Context.MODE_PRIVATE);
		Editor editor = prefs.edit();

		editor.putString("version", getVersionName(activity));
		editor.putString("profile_list", gGson.toJson(gProfileList));
		editor.putString("airdata", gGson.toJson(gAirdataHash));
		editor.putInt("last_server_message_code", gLastServerMessageCode);
		editor.putLong("last_update_message_time", gLastUpdateMessageTime);
		editor.putInt("last_ip_index", GAERequest.mLastIPIndex);
		//			editor.putString("google_ips", TextUtils.join("|", GAERequest.mIPs));
		editor.commit();
	}
	
	public static String getVersionName(Activity activity)
	{
		String ret = "";
		PackageInfo packageInfo;
		try {
			packageInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0);
			ret = packageInfo.versionName;
		} catch (NameNotFoundException e1) {
			Log.e("getPackageInfo failed");
		}
		return ret;
	}
	
	public static int getVersionCode(Activity activity)
	{
		int ret = -1;
		PackageInfo packageInfo;
		try {
			packageInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0);
			ret = packageInfo.versionCode;
		} catch (NameNotFoundException e1) {
			Log.e("getPackageInfo failed");
		}
		return ret;
	}
	
	public static Object[] getMaxPollutant(String id, String standard)
	{
		return getMaxPollutant( getAirdata(id, "hour"), standard);
	}
	// Returns [Name, AQI, cc (mg/m^3)]
	public static Object[] getMaxPollutant(AirData airdata, String standard)
	{
		if( airdata == null ) {
			// Could be null if first update failed
			return new Object[]{"",0, 0f};
		}
		
		Integer maxaqi = 0;
		Float maxcc = 0f;
		String maxname = "";
		for(String name:gItemNameList) {
			if(airdata.getData(name)==null || airdata.getData(name).size() == 0)
				continue;
			float cc = airdata.getData(name).get(airdata.getLength()-1);
			int aqi = AQI.getAQI(name, cc, standard);
			if( aqi > maxaqi ) {
				maxaqi = aqi;
				maxcc = cc;
				maxname = name;
			}
		}
		return new Object[]{maxname, maxaqi, maxcc};
	}
	
	public static String getPollutantDisplayName(String name)
	{
		for(int i = 0; i < gItemNameList.length; i++) {
			if(name.compareTo(gItemNameList[i])==0)
				return gItemDisplayNameList[i];
		}
		return "";
	}
	
	public static long getPollutantDisplayColor(String name)
	{
		for(int i = 0; i < gItemNameList.length; i++) {
			if(name.compareTo(gItemNameList[i])==0)
				return gItemDisplayColorList[i];
		}
		return 0;
	}
	
	public static HashMap<String, String> getLocationInfo(String id)
	{
		for(HashMap<String, String> location : gLocationList) {
			if( id.compareTo(location.get("id")) == 0) {
				return location;
			}
		}
		return null;
	}
	
	public static Float calcAverage(String locId, String airType) {
		List<Float> list = getAirdata(locId, "hour").getData(airType);
		int index = list.size() - 1;
		int length = Math.min(24, list.size());
		
		float sum = 0.0f;
		int num = 0;
		for(int i=0;i<length;i++) {
			float value = list.get(index-i);
			if (Float.compare(value, 0f) > 0) {
				sum += value;
				num++;
			}
		}
		return num>0 ? (sum/num) : 0f;
	}
	
	public static void clearAll() {
		gProfileList.clear();
		gLocationList.clear();
		gAirdataHash.clear();
	}
	
	public static Set<String> getPref_SelectPollutants( Context context ) {
	    SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
	    HashSet<String> defaultNameList = new HashSet<String>(Arrays.asList( context.getResources().getStringArray( R.array.pref_select_pollutants_default ) ));
	    HashSet<String> ret = defaultNameList;
	    
	    String namelistStr = sharedPref.getString( context.getString(R.string.pref_name_select_pollutants), "" );
	    if( namelistStr.length() == 0 )
	        ret = defaultNameList;
	    else
	        ret = new HashSet<String>(Arrays.asList(namelistStr.split(MultiSelectListPreference.DEFAULT_SEPARATOR)));
	    Log.i("SelectPollutants: " + ret.toString());
	    return ret;
	}
	
	public static String getPref_AQIStandard( Context context ) {
	    SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
	    String ret = sharedPref.getString( context.getString(R.string.pref_name_aqi_standard), context.getString(R.string.pref_aqi_standard_default) );
	    Log.i("AQI Standard: " + ret);
	    return ret;
	}
	
	public static int getPref_WidgetTranparency( Context context ) {
	    SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
	    int ret = sharedPref.getInt( context.getString(R.string.pref_name_widget_transparency),
	            context.getResources().getInteger(R.integer.pref_widget_transparency_default) );
	    Log.i("WidgetTransparency: " + ret);
	    return ret;
	}
	
	public static String getPref_WidgetClick( Context context ) {
	    SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
	    String ret = sharedPref.getString( context.getString(R.string.pref_name_widget_click), context.getString(R.string.pref_widget_click_default) );
	    Log.i("WidgetClick: " + ret);
	    return ret;
	}
	
	public static int getPref_NotificationThreshold( Context context ) {
	    SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
	    String threshold = sharedPref.getString( context.getString(R.string.pref_name_notification_threshold), context.getString(R.string.pref_notification_threshold_default) );
	    int ret = Integer.parseInt(threshold);
	    Log.i("NotificationThreshold: " + ret);
	    return ret;
	}
	
	public static AirData getAirdata( String id, String time ) {
	    if( gAirdataHash == null ) return null;
	    HashMap<String, AirData> map = gAirdataHash.get(id);
	    if( map == null ) return null;
	    return map.get(time);
	}
	public static void putAirdata( String id, String time, AirData data ) {
	    HashMap<String, AirData> map = gAirdataHash.get(id);
	    if( map == null ) {
	        map =  new HashMap();
	        gAirdataHash.put(id, map);
	    }
	    map.put(time, data);
	}
	public static String getDisplayName(Context context, Calendar cal, int field) {
	    String rc = "N/A";
	    int value = cal.get(field);
	    switch( field ) {
	    case Calendar.HOUR_OF_DAY:
	        rc = Integer.toString(value);
	        break;
	    case Calendar.DAY_OF_MONTH:
	        rc = Integer.toString(value);
	        break;
	    case Calendar.MONTH:
	        rc = (context.getResources().getStringArray(R.array.month_short_name_array))[value];
	        break;
	    }
	    return rc;
	}
}
